package com.xianrenit.xianrenpuzi.sms.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.alibaba.fastjson.JSON;
import com.xianrenit.xianrenpuzi.common.handler.exception.SpzxException;
import com.xianrenit.xianrenpuzi.model.result.ResultCodeEnum;
import com.xianrenit.xianrenpuzi.sms.service.SmsService;
import com.xianrenit.xianrenpuzi.common.util.utils.HttpUtils;
import com.xianrenit.xianrenpuzi.common.util.utils.RegexValidateUtils;
import com.xianrenit.xianrenpuzi.sms.util.SmsProperties;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.HttpResponse;
import org.apache.http.util.EntityUtils;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Service
public class SmsServiceImpl implements SmsService {
    @Resource
    StringRedisTemplate stringRedisTemplate;
    @Override
    public void sendMsg(String phone, Integer type) {
        //1、手机号格式校验：正则表达式
        boolean flag = RegexValidateUtils.checkCellphone(phone);
        if(!flag){
            throw new SpzxException(ResultCodeEnum.SEND_MESSAGE_MOBILE_ERROR,null);
        }
        //判断发送哪种类型的短信
        if(type==null){
            //注册验证码
            sendCode(phone , type);
        }else if(type==1){
            //登录验证码
        }
    }
    //发送注册验证码业务代码
    private void sendCode(String phone, Integer type) {
        String countKey = "spzx:code:count:" + phone;
        String limitKey = "spzx:code:limit:" + phone;
        //        2、如果手机号获取验证码次数超出阈值 不发送
        //验证5分钟内是否获取过验证码
        if(stringRedisTemplate.hasKey(limitKey)){
            throw new SpzxException(ResultCodeEnum.SEND_MESSAGE_LIMIT_ERROR,null);
        }
        //验证手机号获取验证码次数是否超出允许的范围
        String countStr = stringRedisTemplate.opsForValue().get(countKey);
        if(!StringUtils.isEmpty(countStr) && Integer.parseInt(countStr)>=3){
            throw new SpzxException(ResultCodeEnum.SEND_MESSAGE_COUNT_ERROR,null);
        }

        //        3、生成验证码 发送验证码
        String code = RandomUtil.randomNumbers(4);
        long expireTime = 20;
        String paramsStr = "code:"+code+",expire_at:"+expireTime;
        String templateId = SmsProperties.TEMPLATE_ID;
        sendMessageByApi(phone, paramsStr, templateId);
        //        4、缓存验证码到redis
        stringRedisTemplate.opsForValue().set("spzx:code:regist:"+phone,code,expireTime, TimeUnit.MINUTES);
        //        5、更新手机号获取验证码的次数
        // 一天内只能获取3次： 手机号发送验证码次数+1  如果键不存在默认使用0+1

        Long incr = stringRedisTemplate.opsForValue().increment(countKey);
        if(incr.intValue() == 1){
            //手机号第一次获取验证码成功,给键设置24小时的过期时间
            stringRedisTemplate.expire("spzx:code:count:" + phone,1,TimeUnit.DAYS);
        }
        // 5分钟内只能发送一次: 使用一个唯一键 设置过期时间为5分钟
        stringRedisTemplate.opsForValue().set(limitKey,"1",5,TimeUnit.MINUTES);

    }

    private boolean sendMessageByApi(String mobile ,String paramsStr,String templateId){
        String host = SmsProperties.HOST;
        String path = SmsProperties.PATH;
        String method = SmsProperties.METHOD;
        String appcode = SmsProperties.APPCODE;
        Map<String, String> headers = new HashMap<String, String>();
        //最后在header中的格式(中间是英文空格)为Authorization:APPCODE 83359fd73fe94948385f570e3c139105
        headers.put("Authorization", "APPCODE " + appcode);
        //根据API的要求，定义相对应的Content-Type
        headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8");
        Map<String, String> querys = new HashMap<String, String>();
        Map<String, String> bodys = new HashMap<String, String>();
        //"code:1234,expire_at:10"
        bodys.put("content", paramsStr);
        //"CST_qozfh101"
        bodys.put("template_id", templateId);  //该模板为调试接口专用，短信下发有受限制，调试成功后请联系客服报备专属模板
        //"18516617550"
        bodys.put("phone_number",mobile );
        try {
            HttpResponse response = HttpUtils.doPost(host, path, method, headers, querys, bodys);
            //只有状态码为200 并且 响应体json的 status为OK时才代表响应成功
            int statusCode = response.getStatusLine().getStatusCode();
            Map<String,String> result = JSON.parseObject(EntityUtils.toString(response.getEntity()),Map.class);
            if(statusCode!=200 || !"OK".equals(result.get("status"))){
                throw new SpzxException(ResultCodeEnum.FAIL,null);
            }
            //短信发送成功
            return true;
        } catch (Exception e) {
//            e.printStackTrace();
            throw new SpzxException(ResultCodeEnum.FAIL,e);
        }
    }
}
